package com.hyjiacan.tools.apps.dbm.services

import com.hyjiacan.tools.apps.dbm.models.ConnectionModel
import com.hyjiacan.tools.utils.Json
import java.io.File
import java.nio.charset.StandardCharsets
import java.nio.file.Paths

class ConnectionService {

    companion object {
        private const val ROOT_DIR = "config/connections"
        var root: File = File(ROOT_DIR)

        init {
            if (!root.exists()) {
                root.mkdirs()
            }
        }

        private fun toModel(file: File): ConnectionModel {
            return Json.parse(file.readText(StandardCharsets.UTF_8), ConnectionModel::class.java)
        }

        private fun toFile(model: ConnectionModel, file: File) {
            val content = Json.stringify(model)
            file.writeText(content, StandardCharsets.UTF_8)
        }

        private fun getFile(id: Any): File {
            val filename = "${id.toString().padStart(4, '0')}.json"
            return Paths.get(ROOT_DIR, filename).toFile()
        }

        @Synchronized
        private fun getNextId(): Int {
            val files = root.listFiles() ?: return 1

            if (files.isEmpty()) {
                return 1
            }

            if (files.size == 1) {
                return files[0].nameWithoutExtension.toInt() + 1
            }

            return files.reduce { acc, file ->
                val a = acc.name
                val b = file.name
                if (a > b) {
                    return@reduce acc
                } else {
                    return@reduce file
                }
            }.nameWithoutExtension.toInt() + 1
        }

        fun all(): List<ConnectionModel> {
            val files = root.listFiles() ?: return emptyList()
            return files.filter {
                return@filter it.isFile && it.name.endsWith(".json")
            }.map { toModel(it) }
        }

        fun get(id: Int): ConnectionModel? {
            val file = getFile(id)
            if (!file.exists()) {
                return null
            }

            return toModel(file)
        }

        fun set(connection: ConnectionModel) {
            if (isLabelExists(connection.label, connection.id)) {
                throw Exception("连接名称已经存在")
            }
            if (connection.id == 0 || connection.id == -1) {
                connection.id = getNextId()
            }

            val file = getFile(connection.id)

            toFile(connection, file)
        }

        private fun isLabelExists(label: String, id: Int?): Boolean {
            val hasId = id == null || id == -1
            val connections = all()
            return connections.any {
                if (!hasId && it.label == label) {
                    return@any false
                }
                return@any it.id != id && it.label == label
            }
        }

        fun remove(id: Int) {
            val file = getFile(id)
            if (file.exists()) {
                file.delete()
            }
        }
    }
}